<?php
/*
* Kusht Mud.
* ----
* The MIT License
* Copyright (c) 2010 Andrew Tutt
* ----
*/

/* Commands
*
* This Class Gives Functionality to All of the Game's Commands
*/

/* These commands are overloaded in the architecture in that
* all characters, including NPCs, can issue commands (a good thing)
* so $user could be a userCharacter extends Character or it could be
* a vanilla "Character" object. Pretty neat. */

/* Every time you add a command, you must add a function here. That command
* is automatically associated to the function of the same name */

class commands {

	public static $CMDLIST = array("newbie","ask","answer","auction","music","chat","gossip",
	"shout","yell","hacker","immtalk","say","gtell","emote","tell","reply","recall","rest",
	"stand","sleep","sit","quiet","help","qui","quit",
								   
	// Editor commands
	"_getroomid", "_goto", "_dig", "_newexit", "_pointexit", "_rmvexit", "_newroom", "_nameroom", 
	"_describeroom", "_getroomlist");

	public static $ABBREVS = array("'" => "say",
								   "." => "chat",
								   // _ is a reserved symbol, do not use (for devcmds)
								   ";" => "gtell",
								   "," => "emote",
								   "?" => "help",
								   "/" => "recall");
								   

	/* Associated Functions ------------- */

	/* Communication Functions */
	// Generic Talk Channel
	public static function talk_channel($user, $phrase, $channel, $verb) {
		$buffer="";
		$position;
		
		if ($phrase == "") {
			if($user->has($channel)) { // Do they have the channel off?
				$user->send("You have turned on the ".$verb." channel");
				$user->rmv($channel);
			} else {
				$user->send("You have turned off the ".$verb." channel");
				$user->set($channel);
			}
			return;
		}
		
		// If silent tell them they can't (future update)
		// If deaf, they can't hear this (future update)
	
		switch($channel) {
		default:
			$user->send("You ".$verb.", \"".$phrase."\"");
			$buffer="?n ".$verb."s, '?t'.";
			break;
		// Eventually we'll do a special switch for immtalk
		}	
		
		// Eventually we'll limit the range of rooms that can hear a particular channel (future update)
		$users = World::$char_list;
		foreach ($users as $oUser) {
			if($oUser!==$user) {
				// Return if the Receiver is in QUIET mode
				if($oUser->has(CHANNEL_QUIET)) { continue; }
				// Return if Receiver has the channel off
				if($oUser->has($channel)) { continue; }
				// Eventually we'll check: If the receiver is deaf, etc. 		
				// For limited range channels, we'll follow all the exits out to a certain level of depth of nearby rooms
				// For certain channels the minimum position will be higher than DEAD and we'll check for that
				cmdHandler::act ($user, $buffer, $phrase, $oUser, TO_TARG);
			}
		}
		return;
	}	
	
	// -------------- Commands in Matching Order //
	
	// Talk Channels
	
	public static function newbie($user,$phrase) {
		commands::talk_channel ($user, $phrase, CHANNEL_NONEWBIE, "newbie");
		return;
	}

	public static function ask($user,$phrase) {
		commands::talk_channel ($user, $phrase, CHANNEL_NOQUESTION, "ask");
		return;
	}
	
	public static function answer($user,$phrase) {
		commands::talk_channel ($user, $phrase, CHANNEL_NOQUESTION, "answer");
		return;
	}
	
	public static function auction($user,$phrase) {
		commands::talk_channel ($user, $phrase, CHANNEL_NOAUCTION, "auction");
		return;
	}
	
	public static function music($user,$phrase) {
		commands::talk_channel ($user, $phrase, CHANNEL_NOMUSIC, "music");
		return;
	}

	public static function chat($user,$phrase) {
		commands::talk_channel ($user, $phrase, CHANNEL_NOCHAT, "chat");
		return;
	}
	
	public static function gossip($user,$phrase) {
		commands::talk_channel ($user, $phrase, CHANNEL_NOGOSSIP, "gossip");
		return;
	}

	public static function shout($user,$phrase) {
		commands::talk_channel ($user, $phrase, CHANNEL_NOSHOUT, "shout");
		return;
	}
	
	public static function yell($user,$phrase) {
		commands::talk_channel ($user, $phrase, CHANNEL_NOYELL, "yell");
		return;
	}

	public static function hacker($user,$phrase) {
		commands::talk_channel ($user, $phrase, CHANNEL_NOHACKER, "hack");
		return;
	}

	public static function immtalk($user,$phrase) {
		commands::talk_channel ($user, $phrase, CHANNEL_NOIMMTALK, "immtalk");
		return;
	}

	public static function say($user,$phrase) {
		if($user->in_bad_position(RESTING)) { return; }
		
		if ($phrase == "") {
			$user->send("Say what?");
			return;
		}
		
		cmdHandler::act ($user,"?n says '?T'.", NULL, $phrase, TO_ROOM);
		cmdHandler::act ($user,"You say '?T'.", NULL, $phrase, TO_CHAR);
		
		/* We'll Eventually Toss off a Trigger here too to complete this function */
		/* (for the MOBs) */
	}
	
	public static function gtell($user,$phrase) {
		if ($phrase == "") {
			$user->send("Tell the group what?");
			return;
		}
	}
	
	public static function emote($user,$phrase) {
		// Check to see if the player is allowed to emote (future update)
	
		if ($phrase == "") {
			$user->send("Emote what?");
			return;
		}
		
		cmdHandler::act ($user,"?n ?T.", NULL, $phrase, TO_ROOM);
		cmdHandler::act ($user,"?n ?T.", NULL, $phrase, TO_CHAR);
		return;
	}

	public static function tell($user,$phrase) {
		$arg = cmdHandler::splitReturnNextArg($phrase);
		
		if ($arg=="" || $phrase=="") {
			$user->send("Tell whom what?");
			return;
		}
		
		$target = World::get_char_world($user,$arg);
				
		if (!$target) {
			$user->send("They aren't here.");
			return;
		}
		
		cmdHandler::act ($user,"You tell ?N '?t'.", $phrase, $target, TO_CHAR);
		cmdHandler::act ($user,"?n tells you '?t'.", $phrase, $target, TO_TARG);
		$target->reply = $user;
	}
	
	public static function reply($user,$phrase) {
		if(!isset($user->reply->name)) {
			$user->send("There's no one to reply to.");
			return;
		}
	
		if ($phrase=="") {
			$user->send("Tell them what?");
			return;
		}
		
		commands::tell($user,$user->reply->name." ".$phrase);
	}
	
	public static function recall($user,$phrase) {
		$user->send("We'll add it soon.");
	}
	
	/* Position Changing Commands */
	public static function stand($user, $phrase) {
		if ($user->is(RESTING)) {
			cmdHandler::act ($user,"?n stands up.", NULL, NULL, TO_ROOM);
			$user->send("You stand up.");
			$user->setposition(STANDING);
		} elseif($user->is(SLEEPING)) {
			cmdHandler::act ($user,"?n wakes up, and eases ?mself onto ?s feet.", NULL, NULL, TO_ROOM);
			$user->send("You wake up, and ease yourself onto your feet.");
			$user->setposition(STANDING);
		} elseif($user->is(STANDING)) {
			$user->send("You raise yourself to full height.");
			return;
		} elseif($user->is(FIGHTING)) {
			$user->send("What else would you call trying to avoid dying?");
			return;
		} else {
			$user->send("Are you kidding? You wish you could stand up!");
			return;
		}
		$user->in_room->updatePeopleInside();
	}
	
	public static function rest($user, $phrase) {
		if ($user->is(RESTING)) {
			$user->send("You are about as comfortable as you are going to get without sleeping.");
			return;
		} elseif($user->is(SLEEPING)) {
			cmdHandler::act ($user,"?n opens ?s eyes, and just lays there, awake but unmoving.", NULL, NULL, TO_ROOM);
			$user->send("You open your eyes, and just lay there, awake but unmoving.");
			$user->setposition(RESTING);
		} elseif($user->is(STANDING)) {
			cmdHandler::act ($user,"?n rests.", NULL, NULL, TO_ROOM);
			$user->send("You rest.");
			$user->setposition(RESTING);
		} else {
			$user->send("Are you kidding? You can't rest now!");
			return;
		}
		$user->in_room->updatePeopleInside();
	}
	
	public static function sleep($user, $phrase) {
		if ($user->is(RESTING)) {
			cmdHandler::act ($user,"?n rolls over and goes to sleep.", NULL, NULL, TO_ROOM);
			$user->send("You roll over and go to sleep.");
			$user->setposition(SLEEPING);
		} elseif($user->is(SLEEPING)) {
			$user->send("In your dreams, you dream of sleeping more. My how you love it.");
			return;
		} elseif($user->is(STANDING)) {
			cmdHandler::act ($user,"?n makes ?mself comfortable, closes ?s eyes, and dozes off.", NULL, NULL, TO_ROOM);
			$user->send("You make yourself comfortable, close your eyes, and doze off.");
			$user->setposition(SLEEPING);
		} else {
			$user->send("Are you kidding? You can't sleep now!");
			return;
		}
		$user->in_room->updatePeopleInside();
	}
	
	public static function sit($user, $phrase) {
		if ($user->is(RESTING)) {
			$user->send("You try sitting. It might be slightly more comfortable.");
			return;
		} elseif($user->is(SLEEPING)) {
			cmdHandler::act ($user,"?n opens ?s eyes, and sits up.", NULL, NULL, TO_ROOM);
			$user->send("You open your eyes, and sit up.");
			$user->setposition(RESTING);
		} elseif($user->is(STANDING)) {
			cmdHandler::act ($user,"?n sits down and rests.", NULL, NULL, TO_ROOM);
			$user->send("You sit down and rest.");
			$user->setposition(RESTING);
		} else {
			$user->send("Sitting isn't the top of the priority list right now.");
			return;
		}
		$user->in_room->updatePeopleInside();
	}
	
	/* Setting Toggle Commands */
	
	public static function quiet($user, $phrase) {
		if ($user->has(CHANNEL_QUIET)) {
		      $user->send("Quiet mode removed.");
			  $user->rmv(CHANNEL_QUIET);
		} else {
			 $user->send("From now on, you will only hear says and emotes.");
			 $user->set(CHANNEL_QUIET);
		}
	}
	
	/* Game Commands */
	
	public static function help($user,$phrase) {
		$user->send("We'll add it soon.");
	}
	
	public static function qui($user,$phrase) {
		$user->send("If you want to quit, you have to spell it out.");
	}
	// Eventually we can make it difficult for people to quit but
	// For now, they do it directly
	public static function quit($user,$phrase) {
		ioHandler::doDisconnect($user->connector);
	}

	/* Developer Commands */
	
	public static function _getroomid($user,$arg) {
		$tmp = get_obj_by_stristr($arg,"name",World::$room_list);
		if($tmp) {
			$user->send($tmp->name . " has id " . $tmp->id);
			return;
		} elseif($arg=="") {
			$user->send("This room has id " . $user->in_room()->id);
			return;
		}
		$user->send("That room wasn't found.");
	}
	
	public static function _goto($user,$arg) {
		// Future: Check user permission
		if((int) $arg == 0 ) {
			$tmp = get_obj_by_stristr($arg,"name",World::$room_list);
			if(!$tmp) {
				$user->send("You have to give me something I can work with here.");
				return;
			} 
			cmdHandler::act ($user,"?n disappears with a crack.", NULL, NULL, TO_ROOM);
			$user->move_to($tmp);
			return;
		}
		
		$tmp = get_obj_by_field_value((int)$arg,"id",World::$room_list);
		if(!$tmp) {
			$user->send("Object ID " . $arg . " either isn't a room or it doesn't exist.");
			return;
		}
		cmdHandler::act ($user,"?n disappears with a crack.", NULL, NULL, TO_ROOM);
		$user->move_to($tmp);
	}
	
	// Autocreate the new room and appropriate exit in the new direction
	// _dig "exit name" creates a back-linked room there
	public static function _dig($user,$arg) {
		$outexit = new Exit_();
		$returnexit = new Exit_();
	
		if($arg == "north" || $arg == "n") {
			$outexit->setCommonExit(NORTH);
			$returnexit->setCommonExit(SOUTH);
		} elseif ($arg == "south" || $arg == "s") {
			$outexit->setCommonExit(SOUTH);
			$returnexit->setCommonExit(NORTH);
		} elseif ($arg == "east" || $arg == "e") {
			$outexit->setCommonExit(EAST);
			$returnexit->setCommonExit(WEST);
		} elseif ($arg == "west" || $arg == "w") {
			$outexit->setCommonExit(WEST);
			$returnexit->setCommonExit(EAST);
		} elseif ($arg == "up" || $arg == "u") {
			$outexit->setCommonExit(UP);
			$returnexit->setCommonExit(DOWN);
		} elseif ($arg == "down" || $arg == "d") {
			$outexit->setCommonExit(DOWN);
			$returnexit->setCommonExit(UP);
		} elseif ($arg == "go" || $arg == "g") {
			$outexit->setCommonExit(GO);
			$returnexit->setCommonExit(GO);
		} elseif ($arg == "leave" || $arg == "l") {
			$outexit->setCommonExit(LEAVE);
			$returnexit->setCommonExit(ENTER);
		} elseif ($arg == "enter") {
			$outexit->setCommonExit(ENTER);
			$returnexit->setCommonExit(LEAVE);
		} else {
			$user->send("That's not a diggable direction. If you tried one, remember: you're a developer, be lazy, use letters... [nsewup]");
			return;
		}
		
		$returnexit->to_room = $user->in_room();
		$outRoom = new Room();
		array_push($outRoom->exits,$returnexit);
		array_push(World::$room_list,$outRoom);
		World::sortRooms();
		$outexit->to_room = $outRoom;
		array_push($user->in_room()->exits,$outexit);
		$outRoom->put();
		$user->in_room()->put();
		
		$user->move_to($user->in_room()); // A trick to update the client data
		$user->send("Ok, done.");
		
	}
	
	// One of those trixy functions I don't want to write... argh...
	// syntax: _newexit [command] (if common command, it's set as a common command default
	// syntax: _newexit [command] [Name] TO [ID]
	// Where TO [ID] is also optional
	// Example: _newexit go upstairs to 17 will attempt to create a link to room #17
	public static function _newexit($user,$arg) {
		if($arg == "") {
			$user->send("You've gotta give me a command for the exit");
			return;
		}
	
		$cmd = cmdHandler::splitReturnNextArg($arg);
		
		$outexit = new Exit_();
		if($cmd == "north" || $cmd == "n") {
			$outexit->setCommonExit(NORTH);
		} elseif ($cmd == "south" || $cmd == "s") {
			$outexit->setCommonExit(SOUTH);
		} elseif ($cmd == "east" || $cmd == "e") {
			$outexit->setCommonExit(EAST);
		} elseif ($cmd == "west" || $cmd == "w") {
			$outexit->setCommonExit(WEST);
		} elseif ($cmd == "up" || $cmd == "u") {
			$outexit->setCommonExit(UP);
		} elseif ($cmd == "down" || $cmd == "d") {
			$outexit->setCommonExit(DOWN);
		} elseif ($cmd == "go" || $cmd == "g") {
			$outexit->setCommonExit(GO);
		} elseif ($cmd == "leave" || $cmd == "l") {
			$outexit->setCommonExit(LEAVE);
		} elseif ($cmd == "enter") {
			$outexit->setCommonExit(ENTER);
		} else {
			$outexit->command = $cmd;
		}
		
		$cmd2 = cmdHandler::splitReturnNextArg($arg);
		if($cmd2 == "") { 
			$outexit->to_room = $user->in_room();
			array_push($user->in_room()->exits,$outexit);
			$user->in_room()->put();
			$user->move_to($user->in_room()); // A trick to update the client data
			$user->send("Ok, done.");
			return; 
		}
		
		if(!stristr($cmd2,"to")) {
			$outexit->name = $cmd2;
			$outexit->commandtgt = $cmd2;
		} else {
			$room = get_obj_by_field_value((int)$arg,"id",World::$room_list);
			if(!$room) { 
				$user->send("You've linked to an invalid room. Check your syntax and try again.");
				return;
			} else {
				$outexit->to_room = $room;
				array_push($user->in_room()->exits,$outexit);
				$user->in_room()->put();
				$user->move_to($user->in_room()); // A trick to update the client data
				$user->send("Ok, done.");
				return;
			}
		}
		
		$cmd3 = cmdHandler::splitReturnNextArg($arg);
		if($cmd3 == "") { 
			$outexit->to_room = $user->in_room();
			array_push($user->in_room()->exits,$outexit);
			$user->in_room()->put();
			$user->move_to($user->in_room()); // A trick to update the client data
			$user->send("Ok, done.");
			return; 
		}
		
		if(stristr($cmd3,"to")) {
			$room = get_obj_by_field_value((int)$arg,"id",World::$room_list);
			if(!$room) { 
				$user->send("You've linked to an invalid room. Check your syntax and try again.");
				return;
			} else {
				$outexit->to_room = $room;
				array_push($user->in_room()->exits,$outexit);
				$user->in_room()->put();
				$user->move_to($user->in_room()); // A trick to update the client data
				$user->send("Ok, done.");
				return;
			}
		}
		
		$user->send("Err...Something went wrong. Check your syntax.");
		
	}
	
	// Syntax is _pointexit [Exit Name] to [Room ID]
	// Secondary check is on Exit command, but that's bad form
	public static function _pointexit($user,$arg) {
		$exits = $user->in_room()->exits;
		$exitname = cmdHandler::splitReturnNextArg($arg);
		$exit = get_obj_by_stristr($exitname,"name",$exits);
		if(!$exit) { $exit = get_obj_by_field_value($exitname,"command",$exits); }
		if(!$exit) { 
			$user->send("Exit not found.");
			return;
		}
		
		$shouldbeto = cmdHandler::splitReturnNextArg($arg);
		
		if(stristr($shouldbeto,"to")) {
			$room = get_obj_by_field_value((int)$arg,"id",World::$room_list);
			if(!$room) {
				$user->send("That room wasn't found.");
				return;
			} else {
				$exit->to_room = $room;
				$user->in_room()->put();
				$user->move_to($user->in_room()); // A trick to update the client data
				$user->send("Ok, done.");
				return;
			}
		}
		
		$user->send("Err...Something went wrong. Check your syntax.");
	}
	
	// Syntax is _rmvexit [Exit Name]
	// Secondary check is on Exit command, but that's bad form	
		public static function _rmvexit($user,$arg) {
		$exits = $user->in_room()->exits;
		$exitname = cmdHandler::splitReturnNextArg($arg);
		$exit = get_obj_by_stristr($exitname,"name",$exits);
		if(!$exit) { $exit = get_obj_by_field_value($exitname,"command",$exits); }
		if(!$exit) { 
			$user->send("Exit not found.");
			return;
		}
		
		array_del_elem($user->in_room()->exits,get_obj_by_stristr($exitname,"name",$exits));
		$exit->delete();
		$user->in_room()->exits = array();
		$user->in_room()->put();
		$user->move_to($user->in_room()); // A trick to update the client data
		$user->send("Ok, done.");
		return;	
	}
	
	public static function _nameroom($user,$arg) {
		// Future: Check user permission
		$user->in_room()->name = $arg;
		$user->in_room()->put();
		$user->move_to($user->in_room()); // A trick to update the client data
		$user->send("Ok, done.");
	
	}
	
	public static function _describeroom($user,$arg) {
		// Future: Check user permission
		$user->in_room()->description = $arg;
		$user->in_room()->put();
		$user->move_to($user->in_room()); // A trick to update the client data
		$user->send("Ok, done.");
	}
	
	public static function _newroom($user,$arg) {
		// Future: Check user permission
		$r = new Room();
		$r->put();
		array_push(World::$room_list,$r);
		World::sortRooms();
		$user->send("Ok, done. New room created with id " . $r->id . ". You can get there with _goto.");
	}
		
	public static function _getroomlist($user, $arg) {
		// There shouldn't be an arg for this
		
		// Check the user has the correct priviledges
		
		// Send the room list
		clientHandler::roomList($user);
	}
	
	public static function _setflag($user,$arg) {
	
	}
	
	// We might eventually want to remove rooms and exits that are orphaned
	public static function _prunedatabase($user,$phrase) {
		
	}
}
		